package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.gold.service.IGoldProductTypeService;
import cn.wolfcode.luowowo.search.query.GoldProductSearchQuery;
import cn.wolfcode.luowowo.search.repository.GoldProductTemplateRepository;
import cn.wolfcode.luowowo.search.service.IGoldProductSearchService;
import cn.wolfcode.luowowo.search.template.GoldProductTemplate;
import cn.wolfcode.luowowo.search.vo.StaticVo;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author 猫教授
 * @date 2019/8/18 17:18
 */
@Service
public class GoldProductSearchServiceImpl implements IGoldProductSearchService {
    //操作se搜索引擎的共有三个操作方式,分别con底层到上层
    //第一种,是repository接口
    @Autowired
    private GoldProductTemplateRepository repository;
    //第二种是template
    @Autowired
    private ElasticsearchTemplate template;
    //第三种是最底层的
    @Autowired
    private TransportClient client;

    @Reference
    private IGoldProductTypeService goldProductTypeService;

    @Override
    public void save(GoldProductTemplate tt) {
        repository.save(tt);
    }

    @Override
    public AggregatedPage<GoldProductTemplate> selectByKeyword(GoldProductSearchQuery qo, String... fieldName) {
        //<span style='color:coral;'>${a.count}</span>

        return selectByKeyword(qo,"<span style='color:coral;'>","</span>",GoldProductTemplate.class,GoldProductTemplate.INDEX_NAME,GoldProductTemplate.TYPE_NAME,fieldName);
    }

    @Override
    public List<StaticVo> selectGroupByParentType(String parentTypeId, String parentTypeName) {
        return QueryGroupBy2Fieid(parentTypeId,parentTypeName);
    }

    @Override
    public List<StaticVo> selectGroupByType(String typeId, String typeName,GoldProductSearchQuery qo) {
        if(qo.getType()==-1){
            return QueryGroupBy2Fieid(typeId,typeName);
        }else{
            List<StaticVo> types=new ArrayList<>();
            List<StaticVo> staticVos = QueryGroupBy2Fieid(typeId, typeName);
            for (StaticVo vo : staticVos) {
                Long parentId=goldProductTypeService.selectParentId(vo.getId());
                if (parentId==qo.getProductTypeId()){
                    types.add(vo);
                }

            }
            return types;

        }
    }

    @Override
    public Page<GoldProductTemplate> selectOrderBy(GoldProductSearchQuery qo) {
        NativeSearchQueryBuilder builder =new NativeSearchQueryBuilder();
        builder.withIndices(GoldProductTemplate.INDEX_NAME);
        builder.withTypes(GoldProductTemplate.TYPE_NAME);
        builder.withPageable(qo.getPageableWithoutSort());
        if (qo.getOrderBy()==1){
            builder.withSort(SortBuilders.fieldSort("salesNum").order(SortOrder.DESC));
        }else if(qo.getOrderBy()==2){
            builder.withSort(SortBuilders.fieldSort("actualPrice").order(SortOrder.DESC));
        }else if(qo.getOrderBy()==3){
            builder.withSort(SortBuilders.fieldSort("actualPrice").order(SortOrder.ASC));
        }
        Page<GoldProductTemplate> templates = template.queryForPage(builder.build(), GoldProductTemplate.class);


        return templates;
    }

    @Override
    public Page<GoldProductTemplate> selectOrderByParentTypeId(GoldProductSearchQuery qo) {
        NativeSearchQueryBuilder builder =new NativeSearchQueryBuilder();
        builder.withIndices(GoldProductTemplate.INDEX_NAME);
        builder.withTypes(GoldProductTemplate.TYPE_NAME);
        builder.withPageable(qo.getPageableWithoutSort());
        builder.withQuery(QueryBuilders.matchQuery("parentTypeId",qo.getProductTypeId()));
        if (qo.getOrderBy()==1){
            builder.withSort(SortBuilders.fieldSort("salesNum").order(SortOrder.DESC));
        }else if(qo.getOrderBy()==2){
            builder.withSort(SortBuilders.fieldSort("actualPrice").order(SortOrder.DESC));
        }else if(qo.getOrderBy()==3){
            builder.withSort(SortBuilders.fieldSort("actualPrice").order(SortOrder.ASC));
        }
        Page<GoldProductTemplate> templates = template.queryForPage(builder.build(), GoldProductTemplate.class);
        return templates;
    }

    @Override
    public Page<GoldProductTemplate> selectOrderByTypeId(GoldProductSearchQuery qo) {
        NativeSearchQueryBuilder builder =new NativeSearchQueryBuilder();
        builder.withIndices(GoldProductTemplate.INDEX_NAME);
        builder.withTypes(GoldProductTemplate.TYPE_NAME);
        builder.withPageable(qo.getPageableWithoutSort());
        builder.withQuery(QueryBuilders.matchQuery("typeId",qo.getTypeId()));
        if (qo.getOrderBy()==1){
            builder.withSort(SortBuilders.fieldSort("salesNum").order(SortOrder.DESC));
        }else if(qo.getOrderBy()==2){
            builder.withSort(SortBuilders.fieldSort("actualPrice").order(SortOrder.DESC));
        }else if(qo.getOrderBy()==3){
            builder.withSort(SortBuilders.fieldSort("actualPrice").order(SortOrder.ASC));
        }
        Page<GoldProductTemplate> templates = template.queryForPage(builder.build(), GoldProductTemplate.class);
        return templates;
    }

    @Override
    public String[] searchArrays(String content) {

        NativeSearchQueryBuilder builder =new NativeSearchQueryBuilder();
        builder.withIndices(GoldProductTemplate.INDEX_NAME);
        builder.withTypes(GoldProductTemplate.TYPE_NAME);
        builder.withPageable(PageRequest.of(0,5));
        builder.withQuery(QueryBuilders.multiMatchQuery(content,"productName","subTitle","parentTypeName"));
        Page<GoldProductTemplate> templates = template.queryForPage(builder.build(), GoldProductTemplate.class);
        List<GoldProductTemplate> list = templates.getContent();
        if (list.size()>0){
            String[] str = new String[list.size()*3];
//            for (int i = 0;i<list.size(); i++) {
//                    str[i]=list.get(i).getProductName();
//                    str[i+5]=list.get(i).getParentTypeName();
//
//                    str[i+10]=list.get(i).getSubTitle();
//
//            }
            for (int i = 0;i<list.size(); i++) {
//                if(i==0){
//                    str[i]=list.get(i).getProductName();
//                    str[i+1]=list.get(i).getParentTypeName();
//
//                    str[i+2]=list.get(i).getSubTitle();
//                }else {

                    str[i*3]=list.get(i).getProductName();
                    str[i*3+1]=list.get(i).getParentTypeName();

                    str[i*3+2]=list.get(i).getSubTitle();

            }
            return str;
        }
        return null;
    }


//    @Override
//    public AggregatedPage<TravelTemplate> selectByKeyword(IndexSearchQuery qo, String... fieldName) {
//
//
//        return searchQueryService.selectByKeyword(qo,"<span style='color:red;'>","</span>",TravelTemplate.class,TravelTemplate.INDEX_NAME,TravelTemplate.TYPE_NAME,fieldName);
//    }



    private List<StaticVo> QueryGroupBy2Fieid(String id, String name) {

        //首先第一步我们先建立一个最外围的花括号
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        /**
         * 一定要排除那个其他索引库,不然会直接查询其他索引库的
         *
         */
        builder.withIndices(GoldProductTemplate.INDEX_NAME);
        builder.withTypes(GoldProductTemplate.TYPE_NAME);
        //第二步我们建立composite模块
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();

        //第三步我们建立分组
        //第一个分组对象
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");
        //是否忽略分组
        idSource.missingBucket(true);
        //添加分组字段
        idSource.field(id);
        sources.add(idSource);
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");
        //是否忽略分组
        nameSource.missingBucket(true);
        //添加分组字段
        nameSource.field(name);
        sources.add(nameSource);

        CompositeAggregationBuilder composi = new CompositeAggregationBuilder("selectBytheme", sources);
        //然后再把那个分组的需求加进buidler查询对象

        /**
         * 设置显示条数
         */
        composi.size(50);
        builder.addAggregation(composi);
        //然后进行查询并解析他的结果
        Aggregations aggregations = template.query(builder.build(), response -> {
            return response.getAggregations();
        });
        ArrayList<StaticVo> themeList = new ArrayList();
        InternalComposite selectBytheme = aggregations.get("selectBytheme");
        for (CompositeAggregation.Bucket group : selectBytheme.getBuckets()) {
            StaticVo staticVo = new StaticVo();
            System.out.println(group.getKey());
            /**
             * 这里要注意对为空的进行排除,第一个就会出现为空的情况
             */
            //if (group.getKey().get("id") != null && group.getKey().get("name") != null) {
                staticVo.setId(Long.parseLong(group.getKey().get("id").toString()));
                staticVo.setName(group.getKey().get("name").toString());
                staticVo.setCount(group.getDocCount());
                themeList.add(staticVo);
           // }
        }
        //第一个完善的点排序
        themeList.sort((StaticVo v1, StaticVo v2) -> {
            return Integer.parseInt(v2.getCount() - v1.getCount() + "");
        });
        return themeList;
    }


/**
 * 私有化专用拿来商品高亮关键字查询的
 */
public <T> AggregatedPage<T> selectByKeyword(GoldProductSearchQuery qo, String preTag, String postTag, Class<T> clz, String Indices, String Types, String...fieldName) {
    NativeSearchQueryBuilder builder=new NativeSearchQueryBuilder();
    builder.withIndices(Indices);
    builder.withTypes(Types);
    builder.withQuery(QueryBuilders.multiMatchQuery(qo.getKeyword(),fieldName));
    builder.withPageable(qo.getPageableAndSort());
    HighlightBuilder.Field[] fields=new HighlightBuilder.Field[fieldName.length];
    for (int i = 0; i < fields.length; i++) {
        fields[i]=new HighlightBuilder.Field(fieldName[i]).preTags(preTag).postTags(postTag);
    }
    builder.withHighlightFields(fields);
    AggregatedPage<T> templates = template.queryForPage(builder.build(),clz, new SearchResultMapper() {
        @Override
        public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> Class, Pageable pageable) {
            SearchHit[] hits = response.getHits().getHits();
            List<T> users = new ArrayList<>();
            for (SearchHit hit : hits) {
                String beanStr = hit.getSourceAsString();
                T bean = JSON.parseObject(beanStr, Class);
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                Collection<HighlightField> values = highlightFields.values();
                for (HighlightField value : values) {
                    String text = value.getFragments()[0].toString();
                    try {
                        BeanUtils.setProperty(bean, value.getName(), text);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
                users.add(bean);
                System.out.println(users);
            }
            return new AggregatedPageImpl<T>(users, qo.getPageableWithoutSort(), response.getHits().getTotalHits());
        }
    });
    return templates;
}
    //这三种别从从下到上是以此的封装关系




}
